package dev.ece.suit.hexmap;

import dev.ece.core.engine.Engine;
import dev.ece.core.shader.DepthShader;
import dev.ece.core.sprite.Sprite;
import dev.ece.core.texture.FBOS;
import dev.ece.util.lib.Vector3f;
import dev.ece.util.tools.Camera;

public class MapSprite extends Sprite<Float, MapModel> {

	/**
	 * 显示范围
	 */
	private int rounds;
	
	private float distance = 0;
	
	private float speed = 0.1f;
	
	private MapModelChunk mapModelChunk;
	
	private DepthShader depthShader;
	
	private HexMapCellShader cellShader;
	
	private HexMapCreviceShader creviceShader;
	
	private HexMapTriangleShader triangleShader;
	
	private HexMapWaterShader waterShader;
	
	private boolean full = true;
	
	public MapSprite(MapModel model) {
		this(model, 1);
	}
	
	public MapSprite(MapModel model, int rounds) {
		super(model);
		this.rounds = rounds;
		this.depthShader = createDepthShader();
		this.cellShader = createCellShader();
		this.creviceShader = createCreviceShader();
		this.triangleShader = createTriangleShader();
		this.waterShader = createWaterShader();
	}

	protected DepthShader createDepthShader() {
		return DepthShader.getDepthShader();
	}
	
	protected HexMapTriangleShader createTriangleShader() {
		return HexMapTriangleShader.createHexMapTriangleShader();
	}
	
	protected HexMapCreviceShader createCreviceShader() {
		return HexMapCreviceShader.createHexMapCreviceShader();
	}
	
	protected HexMapCellShader createCellShader() {
		return HexMapCellShader.createHexMapCellShader();
	}
	
	protected HexMapWaterShader createWaterShader() {
		return HexMapWaterShader.createHexMapWaterShader();
	}
	
	@Override
	public void onLogic(Camera camera) {
		setDistance(getDistance() + Engine.currentTimer().getDalyTime() * getSpeed());
	}

	@Override
	public void onRenderDepthMap(Camera camera) {
		getDepthShader().glUseProgram();
		getDepthShader().glModelViewProjectMatrix();
		if(isFull()) {
			super.onRenderDepthMap(camera);
		} else {
			getMapModelChunk().renderDepthMap();
		}
	}

	@Override
	public void onRender(Camera camera) {
		this.renderCells(getCellShader());
		this.renderDevices(getCreviceShader());
		//this.renderTriangles(getTriangleShader());
	}

	protected void renderCells(HexMapCellShader cellShader) {
		cellShader.glUseProgram();
		cellShader.glModelViewProjectMatrix();
		if(isFull()) {
			getModel().renderCells(cellShader);
		} else {
			getMapModelChunk().renderCells(cellShader);
		}
	}
	
	protected void renderDevices(HexMapCreviceShader creviceShader) {
		creviceShader.glUseProgram();
		creviceShader.glModelViewProjectMatrix();
		if(isFull()) {
			getModel().renderDevices(creviceShader);
		} else {
			getMapModelChunk().renderDevices(creviceShader);
		}
	}
	
	protected void renderTriangles(HexMapTriangleShader triangleShader) {
		triangleShader.glUseProgram();
		triangleShader.glModelViewProjectMatrix();
		if(isFull()) {
			getModel().renderTriangles(triangleShader);
		} else {
			getMapModelChunk().renderTriangles(triangleShader);
		}
	}

	@Override
	public void onRenderAlpha(FBOS defer, Camera camera) {
		//this.renderWaters(getWaterShader(), defer, camera);
	}

	protected void renderWaters(HexMapWaterShader waterShader, FBOS defer, Camera camera) {
		waterShader.glUseProgram();
		waterShader.glModelViewProjectMatrix();
		waterShader.glCamera(camera);
		waterShader.glDefer(defer);
		waterShader.glDistance(distance);
		waterShader.glSkyBox(getModel().getSkybox().getTextureCube());
		waterShader.glNoise(getModel().getTerrainModelCreator().getNoise());
		waterShader.glMaterial(getModel().getTerrainModelCreator().getWaterMaterial());
		if(isFull()) {
			getModel().renderWaters(waterShader);
		} else {
			getMapModelChunk().renderWaters(waterShader);
		}
	}
	
	public void changeMapModelChunk(int row, int col) {
		setMapModelChunk(getModel().createMapModelChunk(row, col, getRounds()));
	}
	
	public void changeMapModelChunk(Vector3f position) {
		setMapModelChunk(getModel().createMapModelChunk(position, getRounds()));
	}
	
	protected MapModelChunk getMapModelChunk() {
		return mapModelChunk;
	}

	protected void setMapModelChunk(MapModelChunk mapModelChunk) {
		this.mapModelChunk = mapModelChunk;
	}

	protected DepthShader getDepthShader() {
		return depthShader;
	}

	protected HexMapCellShader getCellShader() {
		return cellShader;
	}

	protected HexMapCreviceShader getCreviceShader() {
		return creviceShader;
	}

	protected HexMapTriangleShader getTriangleShader() {
		return triangleShader;
	}

	protected HexMapWaterShader getWaterShader() {
		return waterShader;
	}

	protected float getDistance() {
		return distance;
	}

	protected void setDistance(float distance) {
		this.distance = distance;
	}

	public float getSpeed() {
		return speed;
	}

	public void setSpeed(float speed) {
		this.speed = speed;
	}

	public void setRounds(int rounds) {
		this.rounds = rounds;
	}

	public int getRounds() {
		return rounds;
	}

	public boolean isFull() {
		return full;
	}

	public void setFull(boolean full) {
		this.full = full;
	}

	@Override
	public boolean isNormalRender() {
		return true;
	}

	@Override
	public boolean isAlphaRender() {
		return true;
	}

}
